#ifndef ADL_CLOCK_
#define ADL_CLOCK_


/* System Control Block(SCB) modules include Memory Accelerator Module,
Phase Locked Loop, VPB divider, Power Control, External Interrupt,
Reset, and Code Security/Debugging */
#define SCB_BASE_ADDR	0xE01FC000

/* Memory Accelerator Module (MAM) */
#define MAMCR          (*(volatile U32 *)(SCB_BASE_ADDR + 0x000))
#define MAMTIM         (*(volatile U32 *)(SCB_BASE_ADDR + 0x004))
#define MEMMAP         (*(volatile U32 *)(SCB_BASE_ADDR + 0x040))

/* Phase Locked Loop (PLL) */
#define PLLCON         (*(volatile U32 *)(SCB_BASE_ADDR + 0x080))
#define PLLCFG         (*(volatile U32 *)(SCB_BASE_ADDR + 0x084))
#define PLLSTAT        (*(volatile U32 *)(SCB_BASE_ADDR + 0x088))
#define PLLFEED        (*(volatile U32 *)(SCB_BASE_ADDR + 0x08C))

/* Power Control */
#define PCON           (*(volatile U32 *)(SCB_BASE_ADDR + 0x0C0))
#define PCONP          (*(volatile U32 *)(SCB_BASE_ADDR + 0x0C4))

/* Clock Divider */
// #define APBDIV         (*(volatile U32 *)(SCB_BASE_ADDR + 0x100))
#define CCLKCFG        (*(volatile U32 *)(SCB_BASE_ADDR + 0x104))
#define USBCLKCFG      (*(volatile U32 *)(SCB_BASE_ADDR + 0x108))
#define CLKSRCSEL      (*(volatile U32 *)(SCB_BASE_ADDR + 0x10C))
#define PCLKSEL0       (*(volatile U32 *)(SCB_BASE_ADDR + 0x1A8))
#define PCLKSEL1       (*(volatile U32 *)(SCB_BASE_ADDR + 0x1AC))

/* External Interrupts */
#define EXTINT         (*(volatile U32 *)(SCB_BASE_ADDR + 0x140))
#define INTWAKE        (*(volatile U32 *)(SCB_BASE_ADDR + 0x144))
#define EXTMODE        (*(volatile U32 *)(SCB_BASE_ADDR + 0x148))
#define EXTPOLAR       (*(volatile U32 *)(SCB_BASE_ADDR + 0x14C))

/* Reset, reset source identification */
#define RSIR           (*(volatile U32 *)(SCB_BASE_ADDR + 0x180))

/* RSID, code security protection */
#define CSPR           (*(volatile U32 *)(SCB_BASE_ADDR + 0x184))

/* AHB configuration */
#define AHBCFG1        (*(volatile U32 *)(SCB_BASE_ADDR + 0x188))
#define AHBCFG2        (*(volatile U32 *)(SCB_BASE_ADDR + 0x18C))

/* System Controls and Status */
#define SCS            (*(volatile U32 *)(SCB_BASE_ADDR + 0x1A0))


#define SCS_OSCEN	(1 << 5)
#define SCS_OSCSTAT	(1 << 6)

#define PLLCON_PLLE	(1 << 0)
#define PLLCON_PLLC	(1 << 1)


typedef struct {
	U32 MSEL : 15;
	U32 dummy0 : 1;
	U32 NSEL : 8;
	U32 PLLE : 1;
	U32 PLLC : 1;
	U32 PLOCK : 1;
} PLLStatusRegister;


#define PLL_SOURCE_INTERNAL_RC_OSC	0
#define PLL_SOURCE_MAIN_OSC			1
#define PLL_SOURCE_RTC_OSC			2


#define adl_scb_ENABLE_MAIN_OSCILATOR() \
	(SCS |= SCS_OSCEN)

#define adl_scb_IS_MAIN_OSCILATOR_READY() \
	(SCS & SCS_OSCSTAT)

#define adl_scb_SET_PLL_CLOCK_SOURCE(source) \
	(CLKSRCSEL = source)

#define adl_scb_GET_PLL_CLOCK_SOURCE() \
	(CLKSRCSEL)

#define adl_scb_ENABLE_PLL() \
	(PLLCON |= PLLCON_PLLE);\
	PLLFEED = 0xAA;\
	PLLFEED = 0x55;

#define adl_scb_DISABLE_PLL() \
	(PLLCON &= ~PLLCON_PLLE);\
	PLLFEED = 0xAA;\
	PLLFEED = 0x55;

#define adl_scb_CONNECT_PLL() \
	(PLLCON |= PLLCON_PLLC);\
	PLLFEED = 0xAA;\
	PLLFEED = 0x55;

#define adl_scb_IS_PLL_CONNECTED() \
	((*((PLLStatusRegister *)(&PLLSTAT))).PLLC)

#define adl_scb_IS_PLL_LOCKED() \
	((*((PLLStatusRegister *)(&PLLSTAT))).PLOCK)

#define adl_scb_SET_PLL_CONFIGURATION(multiplier, divisor) \
	(PLLCFG = (multiplier & 0x7FFF) | ((divisor & 0xFF) << 16));\
	PLLFEED = 0xAA;\
	PLLFEED = 0x55;

#define adl_scb_GET_ACTUAL_PLL_MUL() \
	((*((PLLStatusRegister *)(&PLLSTAT))).MSEL)

#define adl_scb_GET_ACTUAL_PLL_DIV() \
	((*((PLLStatusRegister *)(&PLLSTAT))).NSEL)

#define adl_scb_SET_CPU_CLOCK_DIVISOR(divisor) \
	(CCLKCFG = divisor)

#define adl_scb_GET_CPU_CLOCK_DIVISOR() \
	(CCLKCFG)

#define adl_scb_SET_USB_CLOCK_DIVISOR(divisor) \
	(USBCLKCFG = divisor)

#endif /*ADL_CLOCK_*/
